package com.motong.gongdan.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.util.IoUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.motong.gongdan.config.ResponseData;
import com.motong.gongdan.entity.*;
import com.motong.gongdan.enums.ObjectType;
import com.motong.gongdan.mapper.WorkReportMapper;
import com.motong.gongdan.util.*;
import com.motong.gongdan.vo.H5Resp.H5ReportDetailResp;
import com.motong.gongdan.vo.H5Vo.common.GroupCountVo;
import com.motong.gongdan.vo.H5Vo.customfield.RadioOptionVo;
import com.motong.gongdan.vo.resp.ProduceReportResp;
import com.motong.gongdan.vo.resp.ReportDetailResp;
import com.motong.gongdan.vo.resp.WorkReportListResp;
import com.motong.gongdan.vo.system.CustomEvent.MissionEventMsg;
import com.motong.gongdan.vo.system.CustomField.ColumnsConfigure;
import com.motong.gongdan.vo.system.CustomField.ColumnsConfigureList;
import com.motong.gongdan.vo.system.DataBoard.query.WorkReportGroupByProcessQuery;
import com.motong.gongdan.vo.system.DataBoard.vo.ReportGroupProcessInfo;
import com.motong.gongdan.vo.system.DataBoard.vo.WorkReportDetailVo;
import com.motong.gongdan.vo.system.otherVo.*;
import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author:fff
 * @time:2022/3/7
 */
@Service
public class WorkReportService extends ServiceImpl<WorkReportMapper, WorkReport> {
    @Resource
    WorkReportService workReportService;
    @Resource
    ReportBadProductService reportBadProductService;
    @Resource
    BadProductService badProductService;
    @Resource
    MissionService missionService;
    @Resource
    WorkOrderService workOrderService;
    @Resource
    HandleLogService handleLogService;
    @Resource
    ProcessesService processesService;
    @Resource
    UserService userService;
    @Resource
    CustomEventService customEventService;
    @Resource
    CustomFieldService customFieldService;
    @Resource
    FormCheckRuleService formCheckRuleService;
    @Resource
    DictService dictService;
    @Resource
    WagesService wagesService;
    @Resource
    ProductService productService;
    @Resource
    MongoTemplate mongoTemplate;
    @Resource
    private StockMsgService stockMsgService;
    @Resource
    private StockDetailService stockDetailService;
    @Resource
    private ProcessRouteService processRouteService;
    @Resource
    private ScreenPlanService screenPlanService;

    @Resource
    private WorkReportMapper workReportMapper;

    public ReportDetailResp getReportDetail(Integer id) {
        ReportDetailResp rdr = workReportService.getBaseMapper().getReportDetail(id, LoginUtil.getLoginUserFactory());
        if (rdr != null) {
            if (rdr.getWagesId() != null) {
                rdr.setExpectWages(BigDecimal.ZERO);
                if (rdr.getUnitPrice() != null && rdr.getPricingMethod() == 0 && rdr.getReportNumber() != null && rdr.getGoodProductNumber().compareTo(BigDecimal.valueOf(0)) == 1) {
                    //预计工资
                    rdr.setExpectWages(rdr.getUnitPrice().multiply(rdr.getGoodProductNumber().setScale(2, BigDecimal.ROUND_DOWN)));
                } else if (rdr.getUnitPrice() != null && rdr.getPricingMethod() == 1 && rdr.getReportStartTime() != null && rdr.getReportEndTime() != null) {
                    //计算时间
                    Double minutes = TimeUtil.getDateSubMinutes(TimeUtil.getDateDefaultString(rdr.getReportStartTime()), TimeUtil.getDateDefaultString(rdr.getReportEndTime()));
                    BigDecimal minPrice = rdr.getUnitPrice().divide(BigDecimal.valueOf(60), 2, BigDecimal.ROUND_DOWN);
                    rdr.setExpectWages(minPrice.multiply(BigDecimal.valueOf(minutes)).setScale(2, BigDecimal.ROUND_DOWN));
                }
            }
            List<ReportBadProduct> list = reportBadProductService.list(new QueryWrapper<ReportBadProduct>().eq("work_report_id", rdr.getId()));
            if (!CollectionUtils.isEmpty(list)) {
                list.forEach(l -> {
                    BadProduct badProduct = badProductService.getById(l.getBadProductId());
                    l.setName(badProduct.getName());
                });
                rdr.setList(list);
            }
            if (StringUtil.isNotBlank(rdr.getOther())) {
                rdr.setCustomFieldVos(customFieldService.handleCustomFieldForList(rdr.getOther()));
            }
        }
        return rdr;
    }

    /**
     * H5报工详情
     *
     * @param id
     * @return
     */
    public H5ReportDetailResp getH5ReportDetail(Integer id) {
        H5ReportDetailResp h5ReportDetail = workReportService.getBaseMapper().getH5ReportDetail(id, LoginUtil.getLoginUserFactory());
        if (h5ReportDetail != null) {
            if (h5ReportDetail.getWagesId() != null) {
                h5ReportDetail.setExpectWages(BigDecimal.ZERO);
                if (h5ReportDetail.getUnitPrice() != null && h5ReportDetail.getPricingMethod() == 0 && h5ReportDetail.getReportNumber() != null && h5ReportDetail.getGoodProductNumber().compareTo(BigDecimal.valueOf(0)) == 1) {
                    //预计工资
                    h5ReportDetail.setExpectWages(h5ReportDetail.getUnitPrice().multiply(h5ReportDetail.getGoodProductNumber().setScale(2, BigDecimal.ROUND_DOWN)));
                } else if (h5ReportDetail.getUnitPrice() != null && h5ReportDetail.getPricingMethod() == 1 && h5ReportDetail.getReportStartTime() != null && h5ReportDetail.getReportEndTime() != null) {
                    //计算时间
                    Double minutes = TimeUtil.getDateSubMinutes(TimeUtil.getDateDefaultString(h5ReportDetail.getReportStartTime()), TimeUtil.getDateDefaultString(h5ReportDetail.getReportEndTime()));
                    BigDecimal minPrice = h5ReportDetail.getUnitPrice().divide(BigDecimal.valueOf(60), 2, BigDecimal.ROUND_DOWN);
                    h5ReportDetail.setExpectWages(minPrice.multiply(BigDecimal.valueOf(minutes)).setScale(2, BigDecimal.ROUND_DOWN));
                }
            }
            List<ReportBadProduct> list = reportBadProductService.list(new QueryWrapper<ReportBadProduct>().eq("work_report_id", h5ReportDetail.getId()));
            if (!CollectionUtils.isEmpty(list)) {
                list.forEach(l -> {
                    BadProduct badProduct = badProductService.getById(l.getBadProductId());
                    l.setName(badProduct.getName());
                });
                h5ReportDetail.setList(list);
            }
            if (StringUtil.isNotBlank(h5ReportDetail.getOther())) {
                h5ReportDetail.setCustomFieldVos(customFieldService.handleCustomFieldForList(h5ReportDetail.getOther()));
            }
        }
        return h5ReportDetail;
    }


    public ResponseData<?> handleWorkReport(HandleLog hl, Mission mission, WorkReportHandleVo vo) {
        Processes processes = processesService.getOne(new QueryWrapper<Processes>().eq("code", mission.getProcessCode()));
        WorkReport wr = new WorkReport();
        // 第一次报工修改实际开始时间
        if (mission.getProcessState() == 0) {
            mission.setActualStartTime(new Date());
        }
        WorkReport oriWorkReport = new WorkReport();
        if (vo.getId() == null) {
            if (StringUtil.isNotBlank(vo.getProduceUsers())) {
                WorkReport finalWr1 = wr;
                WorkReport finalWr2 = wr;
                Arrays.asList(vo.getProduceUsers().split(",")).forEach(f -> {
                    handleWorkReport(hl, mission, vo, processes, finalWr1);
                    handleWorkReportSecond(hl, mission, vo, finalWr2, true, null);
                });
                MissionEventMsg msg = new MissionEventMsg();
                msg.setTitle("新增多人报工");
                msg.setWorkOrderCode(vo.getWorkOrderCode());
                msg.setProcessName(mission.getProcessName());
                msg.setText("创建报工良品数" + vo.getGoodProductNumber());
                List<User> userList = userService.listByIds(Arrays.asList(vo.getProduceUsers().split(",")));
                msg.setUser(userList.stream().map(User::getName).collect(Collectors.joining(",")));
                msg.setMsg("请查看详情");
                return ResponseData.success("success");
            } else {
                handleWorkReport(hl, mission, vo, processes, wr);
            }
        } else {
            hl.setHandleCode(vo.getId().toString()).setHandleType("编辑报工");
            wr = workReportService.getById(vo.getId());
            List<String> handleDetail = new ArrayList<>();
            oriWorkReport = JSONUtil.toBean(JSONUtil.toJsonStr(wr), WorkReport.class);
            if (vo.getReportNumber() != null && !(vo.getReportNumber().compareTo(wr.getReportNumber()) == 0)) {
                handleDetail.add("【" + mission.getWorkOrderCode() + "】" + "【报工数】修改为【" + vo.getReportNumber() + "】");
            }
            if (vo.getGoodProductNumber() != null && !(vo.getGoodProductNumber().compareTo(wr.getGoodProductNumber()) == 0)) {
                if (vo.getGoodProductNumber().compareTo(mission.getPlanedNumber()) == 1) {
                    return ResponseData.fail(500, "报工良品数不可超过任务计划数");
                }
                handleDetail.add("【" + mission.getWorkOrderCode() + "】" + "【良品数】修改为【" + vo.getGoodProductNumber() + "】");
            }
            if (vo.getBadProductNumber() != null && !(vo.getBadProductNumber().compareTo(wr.getBadProductNumber()) == 0)) {
                handleDetail.add("【" + mission.getWorkOrderCode() + "】" + "【不良品数】修改为【" + vo.getBadProductNumber() + "】");
            }
            if (vo.getProduceUser() != null && vo.getProduceUser() != wr.getProduceUser()) {
                User u = userService.getById(vo.getProduceUser());
                handleDetail.add("【" + mission.getWorkOrderCode() + "】" + "【生产人员】修改为【" + u.getName() + "】");
            }
            if (vo.getProcessState() != null && vo.getProcessState() != mission.getProcessState()) {
                String state = "";
                if (vo.getProcessState() == 0) {
                    state = "未开始";
                } else if (vo.getProcessState() == 1) {
                    state = "执行中";
                } else {
                    state = "已结束";
                }
                handleDetail.add("【" + mission.getWorkOrderCode() + "】" + "【工序状态】修改为【" + state + "】");
            }
            if (!CollectionUtils.isEmpty(vo.getBadProductList())) {
                Map<String, Object> map = new HashMap<>();
                WorkReport finalWr = wr;
                vo.getBadProductList().forEach(v -> {
                    BadProduct bp = badProductService.getById(v.getBadProductId());
                    if (bp != null) {
                        ReportBadProduct rbp = reportBadProductService.getOne(new QueryWrapper<ReportBadProduct>()
                                .eq("bad_product_id", v.getBadProductId()).eq("num", v.getNum()).eq("work_report_id", finalWr.getId()));
                        if (rbp == null) {
                            map.put(bp.getName(), v.getNum());
                        }
                    }
                });
                handleDetail.add("【" + mission.getWorkOrderCode() + "】" + "【不良品】修改为【" + JSONObject.parseObject(JSON.toJSONString(map)) + "】");
            }
            if (vo.getStartTime() != null && !vo.getStartTime().equals(wr.getReportStartTime())) {
                handleDetail.add("【" + mission.getWorkOrderCode() + "】" + "【开始时间】修改为【" + TimeUtil.getDateDefaultString(vo.getStartTime()) + "】");
            }
            if (vo.getEndTime() != null && !vo.getEndTime().equals(wr.getReportEndTime())) {
                handleDetail.add("【" + mission.getWorkOrderCode() + "】" + "【结束时间】修改为【" + TimeUtil.getDateDefaultString(vo.getStartTime()) + "】");
            }
            if (vo.getPricingMethod() != null && vo.getPricingMethod() != wr.getPricingMethod()) {
                handleDetail.add("【" + mission.getWorkOrderCode() + "】" + "【计价方式】修改为【" + (vo.getPricingMethod() == 0 ? "计件" : "计时") + "】");
            }
            hl.setHandleDetailList(handleDetail);
            if (vo.getStartTime() != null && vo.getEndTime() != null) {
                wr.setReportStartTime(vo.getStartTime());
                wr.setReportEndTime(vo.getEndTime());
            }
            BigDecimal diff = vo.getGoodProductNumber().subtract(wr.getGoodProductNumber());
            BigDecimal diffBad = vo.getBadProductNumber().subtract(wr.getBadProductNumber());
            mission.setGoodProductNumber(mission.getGoodProductNumber().add(diff));
            mission.setBadProductNumber(mission.getBadProductNumber().add(diffBad));
            SpringUtil.copyPropertiesIgnoreNull(vo, wr);
        }
        handleWorkReportSecond(hl, mission, vo, wr, false, oriWorkReport);
        mission.setProcessName(processes.getName());
        customEventService.sendCustomEventMsg(1, 0, 1, null, mission, null);
        return ResponseData.success("success");
    }

    public void handleWorkReportSecond(HandleLog hl, Mission mission, WorkReportHandleVo vo, WorkReport finalWr2, boolean flag, WorkReport oriWorkReport) {
        boolean isUpdate = Objects.nonNull(finalWr2.getId());
        BigDecimal proDifference = null;
        if (vo.getVerifyState() == 1) {
            finalWr2.setVerifyTime(new Date());
            finalWr2.setVerifyUser(LoginUtil.getLoginUserId());
            if (mission.getLast() == 0) {
                if (isUpdate) {
                    proDifference = finalWr2.getGoodProductNumber().subtract(vo.getVerifyState().equals(oriWorkReport.getVerifyState()) ? oriWorkReport.getGoodProductNumber() : BigDecimal.ZERO);
                } else {
                    proDifference = finalWr2.getGoodProductNumber();
                }
                productService.rectifyStockByDifference(proDifference, mission.getProductCode());
            }
        } else if (vo.getVerifyState() == 0 && isUpdate && mission.getLast() == 0) {
            if (!vo.getVerifyState().equals(oriWorkReport.getVerifyState())) {
                productService.rectifyStockByDifference(oriWorkReport.getGoodProductNumber().negate(), mission.getProductCode());
            }
        }
        if (StringUtil.isNotBlank(vo.getActualEfficiency())) {
            finalWr2.setActualEfficiency(vo.getActualEfficiency());
        }
        if (StringUtil.isNotBlank(vo.getStandardRate())) {
            finalWr2.setStandardRate(vo.getStandardRate());
        }
        if (!CollectionUtils.isEmpty(vo.getCustomFieldVos())) {
            finalWr2.setOther(customFieldService.handleObjectCreateOrEdit(vo.getCustomFieldVos()).toJSONString());
        } else {
            finalWr2.setOther("");
        }
        workReportService.saveOrUpdate(finalWr2);
        if (Objects.nonNull(proDifference)) {
            Product product = productService.getOne(new LambdaQueryWrapper<Product>().eq(Product::getCode, mission.getProductCode())
                    .eq(Product::getDelFlag,0));
            if (Objects.nonNull(product)) {
                stockDetailService.rectifyStockByDifference(proDifference, product.getId(), finalWr2.getId().toString());
            }
        }
        if (!flag) {
            customEventService.sendCustomEventMsg(2, 0, 0, null, mission, finalWr2);
        }
        if (!CollectionUtils.isEmpty(vo.getCustomFieldVos())) {
            WorkReport workReport = new WorkReport();
            workReport.setId(finalWr2.getId());
            workReport.setCustomFieldMess(JSONArray.parseArray(finalWr2.getOther()));
            mongoTemplate.save(workReport);
        }
        if (!CollectionUtils.isEmpty(hl.getHandleDetailList())) {
            hl.getHandleDetailList().forEach(h -> {
                HandleLog handleLog = new HandleLog();
                SpringUtil.copyPropertiesIgnoreNull(hl, handleLog);
                handleLog.setHandleDetail(h);
                handleLogService.save(handleLog);
            });
        } else {
            hl.setHandleCode(finalWr2.getId().toString());
            handleLogService.save(hl);
        }
        if (!CollectionUtils.isEmpty(vo.getBadProductList())) {
            if (finalWr2.getId() != null) {
                List<ReportBadProduct> list = reportBadProductService.list(new QueryWrapper<ReportBadProduct>().eq("work_report_id", finalWr2.getId()));
                if (!CollectionUtils.isEmpty(list)) {
                    reportBadProductService.removeByIds(list.stream().map(ReportBadProduct::getId).collect(Collectors.toList()));
                }
            }
            WorkReport finalWr = finalWr2;
            vo.getBadProductList().forEach(b -> {
                ReportBadProduct rbp = new ReportBadProduct();
                rbp.setWorkReportId(finalWr.getId());
                rbp.setBadProductId(b.getBadProductId());
                rbp.setNum(b.getNum());
                reportBadProductService.save(rbp);
            });
        }
        WorkOrder wo = workOrderService.getOne(new QueryWrapper<WorkOrder>().eq("code", mission.getWorkOrderCode()));
        if (vo.getProcessState() != null) {
            mission.setProcessState(vo.getProcessState());
            missionService.updateById(mission);
        }
        if (mission.getLast() == 0 && mission.getPlanedNumber().compareTo(mission.getGoodProductNumber()) < 1) {
            wo.setActualEndTime(new Date());
        }
        if (mission.getProcessState() == 0 && mission.getPlanedNumber().compareTo(vo.getGoodProductNumber()) == 1) { //大于
            mission.setProcessState(1);
        } else if (mission.getProcessState() == 0 && mission.getPlanedNumber().compareTo(vo.getGoodProductNumber()) < 1) { //小于等于
            mission.setActualEndTime(new Date());
//            mission.setProcessState(2);
        }

        if (mission.getGoodProductNumber().compareTo(mission.getPlanedNumber()) == 0) {
//            mission.setProcessState(2);
            if (mission.getActualEndTime() == null) {
                mission.setActualEndTime(new Date());
            }
        }
        missionService.updateById(mission);

        // 获取当前总工时
        Long totalTime = workOrderService.completeWorkReport(mission.getWorkOrderCode());
        wo.setReportedHours(TimeUtil.cnFormatByTimeExpectDay(totalTime));


        BigDecimal difference = vo.getBadProductNumber().subtract(Objects.nonNull(vo.getId()) ? oriWorkReport.getBadProductNumber() : BigDecimal.ZERO);
        wo.setBadProductNumber(Objects.isNull(wo.getBadProductNumber()) ? vo.getBadProductNumber() : wo.getBadProductNumber().add(difference));
        if (mission.getLast() == 0) {
            wo.setActualNumber(mission.getGoodProductNumber());
            wo.setGoodProductNumber(mission.getGoodProductNumber());
        }
        workOrderService.updateById(wo);
    }


    public static void handleWorkReport(HandleLog hl, Mission mission, WorkReportHandleVo vo, Processes processes, WorkReport finalWr1) {
        hl.setHandleType("创建报工");
        SpringUtil.copyPropertiesIgnoreNull(vo, finalWr1);
        finalWr1.setMissionId(mission.getId());
        finalWr1.setReportStartTime(vo.getStartTime());
        finalWr1.setReportEndTime(vo.getEndTime());
        String dateDefaultString = TimeUtil.getDateDefaultString(new Date());
        finalWr1.setCreateTime(dateDefaultString);

        hl.setHandleDetail("【" + mission.getWorkOrderCode() + "】" + "【" + processes.getName() + "】创建报工成功");
        if (mission.getProcessState() == 0) {
            mission.setProcessState(1);
        }
        mission.setGoodProductNumber(vo.getGoodProductNumber().add(mission.getGoodProductNumber()));
        mission.setBadProductNumber(vo.getBadProductNumber().add(mission.getBadProductNumber()));
    }


    public void handleImport(MultipartFile file) throws IOException, NoSuchFieldException, IllegalAccessException, ExecutionException, InterruptedException {
        byte[] stream = IoUtils.toByteArray(file.getInputStream());

        List<Map<String, String>> allDataList = EasyExcelImportUtils.parseExcelToData(stream, 2, "工单编号");
        // 空值导入日志
        userService.importBlankExcel(allDataList, "workReport");

        List<ColumnsConfigureList> allList = userService.handleDefault();
        Map<String, Integer> dataMap = new HashMap<>();
        List<Map<String, String>> failList = new ArrayList<>();
        int a = 0;
        int b = 0;
        if (allList.stream().filter(f -> f.getType().equals("workReport")).findAny().orElse(null) != null) {
            List<ColumnsConfigure> list = allList.stream().filter(f -> f.getType().equals("workReport")).findAny().orElse(null).getColumns();
            for (Map<String, String> s : allDataList) {
                Map<String, String> failMap = new HashMap<>();
                WorkReport wr = new WorkReport();
                WorkOrder wo = new WorkOrder();
                Mission mission = new Mission();
                List<CustomFieldVo> vos = new ArrayList<>();
                //表头
                List<String> keyList = new ArrayList<>(s.keySet());
                int flag = 0;
                WageReportVo wageVo = new WageReportVo();
                for (int i = 0; i < keyList.size() && flag == 0; i++) {
                    if (i >= list.size()) {
                        CustomField cf = customFieldService.getOne(new QueryWrapper<CustomField>().eq("field_ascription", "workReport").eq("chinese_name", keyList.get(i)));
                        CustomFieldVo vo = new CustomFieldVo();
                        vo.setCustomFieldId(cf.getId());
                        vo.setValue(s.get(keyList.get(i)));
                        vos.add(vo);
                    } else {
                        WorkReportHandleVo vo = new WorkReportHandleVo();
                        vo.setReportNumber(BigDecimal.valueOf(Double.valueOf(s.get(keyList.get(2)))));
                        vo.setGoodProductNumber(BigDecimal.valueOf(Double.valueOf(s.get(keyList.get(4)) == null ? String.valueOf(0) : s.get(keyList.get(4)))));
                        vo.setBadProductNumber(BigDecimal.valueOf(Double.valueOf(s.get(keyList.get(5)) == null ? String.valueOf(0) : s.get(keyList.get(5)))));
                        Processes processes = new Processes();
                        switch (i) {
                            case 0:
                                if (StringUtil.isBlank(s.get(keyList.get(i)))) {
                                    failMap.put("失败原因", "系统内不存在此工单");
                                    failMap.put("工单编号", s.get(keyList.get(i)));
                                    failMap.put("工序名称", s.get(keyList.get(i + 1)));
                                    failMap.put("计价方式", s.get(keyList.get(i + 3)));
                                    failList.add(failMap);
                                    b++;
                                    flag = 1;
                                    break;
                                } else {
                                    wo = workOrderService.getOne(new QueryWrapper<WorkOrder>().eq("code", s.get(keyList.get(i))));
                                    if (wo == null) {
                                        failMap.put("失败原因", "系统内不存在此工单");
                                        failMap.put("工单编号", s.get(keyList.get(i)));
                                        failMap.put("工序名称", s.get(keyList.get(i + 1)));
                                        failMap.put("计价方式", s.get(keyList.get(i + 3)));
                                        failList.add(failMap);
                                        b++;
                                        flag = 1;
                                        break;
                                    }
                                }
                                wageVo.setWordOrderCode(wo.getCode());
                                continue;
                            case 1:
                                if (StringUtil.isNotBlank(s.get(keyList.get(i)))) {
                                    processes = processesService.getOne(new QueryWrapper<Processes>().eq("name", s.get(keyList.get(i))));
                                    if (processes == null) {
                                        failMap.put("失败原因", "系统内不存在此工序");
                                        failMap.put("工单编号", s.get(keyList.get(0)));
                                        failMap.put("工序名称", s.get(keyList.get(i)));
                                        failMap.put("计价方式", s.get(keyList.get(i + 2)));
                                        failList.add(failMap);
                                        b++;
                                        flag = 1;
                                        break;
                                    } else {
                                        wageVo.setProcessesCode(processes.getCode());
                                        List<Mission> missionList = missionService.list(new QueryWrapper<Mission>()
                                                .eq("work_order_code", wo.getCode()).eq("process_code", processes.getCode()));
                                        if (!CollectionUtils.isEmpty(missionList) && missionList.size() > 1) {
                                            for (Mission m : missionList) {
                                                if (m.getGoodProductNumber().compareTo(m.getPlanedNumber()) == -1) {
                                                    mission = m;
                                                    break;
                                                }
                                            }
                                        } else {
                                            mission = missionService.getOne(new QueryWrapper<Mission>()
                                                    .eq("work_order_code", wo.getCode()).eq("process_code", processes.getCode()));
                                        }
                                        Mission before = null;
                                        if (mission.getLast() != 1 && mission.getLast() != 0) {
                                            before = missionService.getOne(new QueryWrapper<Mission>().eq("work_order_code", wo.getCode()).eq("last", mission.getLast() - 1));
                                        } else if (mission.getLast() == 0) {
                                            before = missionService.getOne(new QueryWrapper<Mission>().eq("work_order_code", wo.getCode()).eq("last", wo.getProcessId().split(",").length - 1));
                                        }
                                        Mission checkMission = new Mission();
                                        BeanUtil.copyProperties(mission, checkMission, true);
                                        String result = checkRule(vo, checkMission, before);
                                        if (StringUtil.isNotBlank(result)) {
                                            failMap.put("失败原因", result);
                                            failMap.put("工单编号", s.get(keyList.get(0)));
                                            failMap.put("工序名称", s.get(keyList.get(i)));
                                            failMap.put("计价方式", s.get(keyList.get(i + 2)));
                                            failList.add(failMap);
                                            b++;
                                            flag = 1;
                                            break;
                                        }
                                        wr.setMissionId(mission.getId());
                                        wageVo.setMissionId(mission.getId());
                                    }
                                }
                                continue;
                            case 2:
                                wr.setReportNumber(BigDecimal.valueOf(Double.valueOf(s.get(keyList.get(i)))));
                                continue;
                            case 3:
                                if (s.get(keyList.get(i)).equals("计时")) {
                                    wr.setPricingMethod(1);
                                } else {
                                    wr.setPricingMethod(0);
                                }
                                wageVo.setPricing(wr.getPricingMethod());
                                continue;
                            case 4:
                                wr.setGoodProductNumber(BigDecimal.valueOf(Double.valueOf(s.get(keyList.get(i)) == null ? String.valueOf(0) : s.get(keyList.get(i)))));
                                continue;
                            case 5:
                                wr.setBadProductNumber(BigDecimal.valueOf(Double.valueOf(s.get(keyList.get(i)) == null ? String.valueOf(0) : s.get(keyList.get(i)))));
                                continue;
                            case 6:
                                if (StringUtil.isNotBlank(s.get(keyList.get(i)))) {
                                    User u = userService.getOne(new QueryWrapper<User>().eq("account", s.get(keyList.get(i))).eq("factory_id", LoginUtil.getLoginUserFactory()));
                                    if (u != null) {
                                        wr.setProduceUser(u.getId());
                                        wageVo.setUserId(u.getId().toString());
                                    }
                                }
                                continue;
                            case 7:
                                if (s.get(keyList.get(i)) != null && StringUtil.isNotBlank(s.get(keyList.get(i)))) {
                                    wr.setReportStartTime(TimeUtil.parseDate(TimeUtil.DEFAULT_DATE_FORMAT, s.get(keyList.get(i))) == null ?
                                            TimeUtil.parseDate("yyyy-MM-dd HH:mm", s.get(keyList.get(i))) : TimeUtil.parseDate(TimeUtil.DEFAULT_DATE_FORMAT, s.get(keyList.get(i))));
                                } else {
                                    wr.setReportStartTime(new Date());
                                }
                                continue;
                            case 8:
                                if (StringUtil.isNotBlank(s.get(keyList.get(i)))) {
                                    wr.setReportEndTime(TimeUtil.parseDate(TimeUtil.DEFAULT_DATE_FORMAT, s.get(keyList.get(i))) == null ?
                                            TimeUtil.parseDate("yyyy-MM-dd HH:mm", s.get(keyList.get(i))) : TimeUtil.parseDate(TimeUtil.DEFAULT_DATE_FORMAT, s.get(keyList.get(i))));
                                } else {
                                    wr.setReportEndTime(new Date());
                                }
                                continue;
                            case 9:
                                if ("已审批".equals(s.get(keyList.get(i)))) {
                                    wr.setVerifyState(1);
                                    wr.setVerifyTime(new Date());
                                } else {
                                    wr.setVerifyState(0);
                                }
                                continue;
                            case 10:
                                if (StringUtil.isNotBlank(s.get(keyList.get(i)))) {
                                    wr.setEstimateWage(BigDecimal.valueOf(Double.valueOf(s.get(keyList.get(i)))));
                                }
                                continue;
                            case 11:
                                if (StringUtil.isNotBlank(s.get(keyList.get(i)))) {
                                    wr.setUnfinishedReason(s.get(keyList.get(i)));
                                }
                                continue;
                        }
                    }
                }
                if (flag == 0) {
                    if (!CollectionUtils.isEmpty(vos)) {
                        wr.setOther(customFieldService.handleObjectCreateOrEdit(vos).toJSONString());
                        Map<String, Object> custom = new HashMap<>();
                        custom = vos.stream().filter(v -> StringUtil.isNotBlank(v.getValue())).collect(Collectors.toMap(CustomFieldVo::getCustomFieldId, CustomFieldVo::getValue)).entrySet().stream()
                                .collect(Collectors.toMap(entry -> entry.getKey().toString(), Map.Entry::getValue));
                        wageVo.setCustom(custom);
                    }
                    if (wr.getMissionId() != null && mission != null && wo != null) {
                        Wages w = wagesService.workReportGetWages(wageVo);
                        if (w != null && w.getUnitPrice() != null) {
                            wr.setWagesId(w.getId());
                            if (wr.getPricingMethod() == 0) {
                                wr.setEstimateWage(wr.getGoodProductNumber().multiply(w.getUnitPrice()).setScale(2, BigDecimal.ROUND_UP));
                            } else if (wr.getPricingMethod() == 1 && wr.getReportStartTime() != null && wr.getReportEndTime() != null) {
                                double minutes = TimeUtil.getDateSubMinutes(TimeUtil.getDateDefaultString(wr.getReportStartTime()), TimeUtil.getDateDefaultString(wr.getReportEndTime()));
                                BigDecimal hours = BigDecimal.valueOf(minutes).divide(BigDecimal.valueOf(60, 3));
                                wr.setEstimateWage(hours.multiply(w.getUnitPrice()));
                            }
                        }
                        boolean result = workReportService.save(wr);
                        if (result) {
                            a++;
                            if (StringUtil.isNotBlank(wr.getOther())) {
                                WorkReport workReport = new WorkReport();
                                workReport.setId(wr.getId());
                                workReport.setCustomFieldMess(JSONArray.parseArray(wr.getOther()));
                                mongoTemplate.save(workReport);
                            }
                            if (mission.getLast() == 1) {
                                wo.setActualStartTime(new Date());
                            }
                            if (mission.getLast() == 0 && mission.getPlanedNumber() == mission.getGoodProductNumber()) {
                                wo.setActualEndTime(new Date());
                            }
                            wo.setGoodProductNumber(wo.getGoodProductNumber().add(wr.getGoodProductNumber()));
                            wo.setBadProductNumber(wo.getBadProductNumber().add(wr.getBadProductNumber()));
                            mission.setGoodProductNumber(wr.getGoodProductNumber().add(mission.getGoodProductNumber()));
                            mission.setBadProductNumber(wr.getBadProductNumber().add(mission.getBadProductNumber()));
                            if (mission.getPlanedNumber().compareTo(mission.getGoodProductNumber()) == 0) {
                                mission.setActualEndTime(new Date());
                                mission.setProcessState(2);
                                if (mission.getProcessState() == 0 && mission.getPlanedNumber().compareTo(wr.getGoodProductNumber()) == 1) { //大于
                                    mission.setProcessState(1);
                                } else if (mission.getProcessState() == 0 && mission.getPlanedNumber().compareTo(wr.getGoodProductNumber()) < 1) { //小于等于
                                    mission.setProcessState(2);
                                }
                                if (mission.getActualStartTime() == null) {
                                    mission.setActualStartTime(new Date());
                                }
                                if (mission.getGoodProductNumber() == mission.getPlanedNumber()) {
                                    mission.setProcessState(2);
                                    if (mission.getActualEndTime() == null) {
                                        mission.setActualEndTime(new Date());
                                    }
                                }
                            }
                            // 自动开始工序
                            if (wo.getState() == 1 && (mission.getPlanedNumber().compareTo(mission.getGoodProductNumber()) > 0)) {
                                mission.setProcessState(1);
                            } else {
                                mission.setProcessState(2);
                            }
                            missionService.updateById(mission);
                            workOrderService.updateById(wo);
                        }
                    } else {
                        b++;
                    }
                }
            }
            dataMap.put("createSuccess", a);
            dataMap.put("createFail", b);
            userService.importLog(LoginUtil.getLoginAccount(), allDataList.size(), dataMap, "workReport", failList);
        }
    }


    public String checkRule(WorkReportHandleVo vo, Mission mission, Mission before) throws NoSuchFieldException, IllegalAccessException {
        List<FormCheckRule> formCheckRuleList = formCheckRuleService.list(new QueryWrapper<FormCheckRule>().eq("state", 1));
        if (!CollectionUtils.isEmpty(formCheckRuleList)) {
            // 任务良品数和不良品数加上当前报工
            if (Objects.isNull(vo.getId())) {
                mission.setGoodProductNumber(mission.getGoodProductNumber().add(vo.getGoodProductNumber()));
                mission.setBadProductNumber(mission.getBadProductNumber().add(vo.getBadProductNumber()));
            }
            for (FormCheckRule fcr : formCheckRuleList) {
                if (StringUtil.isNotBlank(fcr.getCheckRule())) {
                    List<String> sList = OwnUtil.extractMessageByRegular(fcr.getCheckRule());
                    String newRule = StringUtil.regReplace(fcr.getCheckRule());
                    for (String s : sList) {
                        Dict dict = dictService.getOne(new QueryWrapper<Dict>().eq("key_s", s));
                        if (dict == null) {
                            break;
                        }
                        if (dict.getUp() == null || (s.contains("报工.任务.") && !dict.getUp().equals("backMission"))) {
                            if (s.contains("报工.任务.") || s.contains("计划数")) {
                                newRule = handleField(mission, dict.getValueS(), newRule, s);
                            } else {
                                newRule = handleField(vo, dict.getValueS(), newRule, s);
                            }
                            fcr.setCheckRule(newRule);
                        } else {
//                            if(dict.getUp().equals("mission")){
//                                newRule = handleField(mission, dict.getValueS(), newRule,s);
//                                fcr.setCheckRule(newRule);
//                            }else
                            if (dict.getUp().equals("backMission")) {
                                if (before == null) {
                                    break;
                                }
                                if (before.getId().equals(mission.getId())) {
                                    break;
                                }
                                newRule = handleField(before, dict.getValueS(), newRule, s);
                                fcr.setCheckRule(newRule);
                            }
                        }
                    }
                    System.out.println(fcr.getCheckRule());
                    boolean chinese = OwnUtil.checkStringContainChinese(fcr.getCheckRule());
                    if (chinese) {
                        continue;
                    }
                    ExecuteStringAsCodeUtils tool = new ExecuteStringAsCodeUtils();
                    boolean res = (boolean) tool.executeString(fcr.getCheckRule(), null);
                    if (res) {
                        return fcr.getErrMsg();
                    }
                } else {
                    continue;
                }
            }
        } else {
            return null;
        }
        return null;
    }

    public String handleField(Object o, String valueS, String newRule, String s) throws NoSuchFieldException, IllegalAccessException {
        Field fields = o.getClass().getDeclaredField(valueS);
        fields.setAccessible(true);
        Integer num = Double.valueOf(Objects.isNull(fields.get(o)) ? "0" : fields.get(o).toString()).intValue();
        String newS = StringUtil.regReplace(s);
        return newRule.replaceAll(newS, num.toString());
    }

    /**
     * 报工表单校验
     *
     * @param formData 表单map数据
     */
    public String verifyForm(Map<String, Object> formData) {

        try {
            List<FormCheckRule> list = formCheckRuleService.list(new LambdaQueryWrapper<FormCheckRule>().eq(FormCheckRule::getState, 1));
            if (Objects.isNull(list) || list.isEmpty()) {
                return null;
            }
            for (FormCheckRule formCheckRule : list) {
                //获取替换后的公式
                RealFormulaVo realFormulaVo = getRealFormula(formCheckRule.getCheckRule().replace("报工.", ""));
                List<String> columnName = realFormulaVo.getColumnName();
                List<CustomField> customFields = realFormulaVo.getCustomFields();
                String realFormula = realFormulaVo.getRealFormula();
                if (rulePass(realFormula, columnName, customFields, formData)) {
                    return formCheckRule.getErrMsg();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param realFormula  最终公式
     * @param columnName   固有字段
     * @param customFields 自定义字段
     */
    public boolean rulePass(String realFormula, List<String> columnName, List<CustomField> customFields, Map<String, Object> formData) throws Exception {
        DefaultContext<String, Object> context = new DefaultContext<>();
        // 自定义表单内容
        List<Map<String, Object>> customFieldVos = (List<Map<String, Object>>) formData.getOrDefault("customFieldVos", Collections.EMPTY_LIST);
        //固有字段不良品和良品
        columnName.forEach(d -> context.put(d, Convert.toBigDecimal(formData.getOrDefault(d, 0))));
        //自定义字段并去除特殊字符
        customFields.forEach(d -> context.put(d.getChineseName().replace("-", "").replace("——", ""),
                Convert.toBigDecimal(customFieldVos.stream().filter(
                        f -> d.getId().toString().equals(f.get("customFieldId").toString())).findFirst().orElse(Collections.EMPTY_MAP).getOrDefault("value", 0))));
        Object execute = new ExpressRunner().execute(realFormula, context, null, true, false);
        return Boolean.parseBoolean(execute.toString());
    }


    /**
     * 获取替换后的公式
     *
     * @param oriFormula 原公式
     */
    // 获取替换完成的公式
    public RealFormulaVo getRealFormula(String oriFormula) {
        List<String> columnName = new ArrayList<>(2);
        List<CustomField> customFields = new ArrayList<>();
        // 替换完成的公式
        String realFormula = oriFormula;
        //自定义列
        List<String> cuColumnName = new ArrayList<>();
        Matcher matcher = Pattern.compile("(?<=\\$\\{)(.+?)(?=})").matcher(oriFormula);
        while (matcher.find()) {
            System.out.println(matcher.group(0));
            switch (matcher.group(0)) {
                case "报工数":
                    realFormula = realFormula.replace("${报工数}", "reportNumber");
                    columnName.add("reportNumber");
                    break;
                case "良品数":
                    realFormula = realFormula.replace("${良品数}", "goodProductNumber");
                    columnName.add("goodProductNumber");
                    break;
                case "不良品数":
                    realFormula = realFormula.replace("${不良品数}", "badProductNumber");
                    columnName.add("badProductNumber");
                    break;
                default:
                    cuColumnName.add(matcher.group(0));
            }
        }
        // 替换自定义字段
        if (!cuColumnName.isEmpty()) {
            customFields = customFieldService.list(new LambdaQueryWrapper<CustomField>().in(CustomField::getChineseName, cuColumnName));
        }
        for (CustomField field : customFields) {
            realFormula = realFormula.replace("${".concat(field.getChineseName()).concat("}"), field.getChineseName());
        }
        String replaceRealFormula = realFormula.replace("-", "").replace("——", "");
        return new RealFormulaVo().setRealFormula(replaceRealFormula).setColumnName(columnName).setCustomFields(customFields);
    }

    /**
     * 报工看板统计信息
     *
     * @param page  分页
     * @param query 请求参数
     */
    public Page<ReportGroupProcessInfo> workReportGroupByProcessList(Page<WorkReport> page, WorkReportGroupByProcessQuery query) {
        ProcessRoute processRoute = processRouteService.getById(query.getProcessRouterId());
        if (Objects.nonNull(processRoute) && StringUtils.hasLength(processRoute.getProcessList())) {
            List<Integer> processIds = JSONUtil.toList(processRoute.getProcessList(), ProcessRoteProcessVo.class).stream().map(ProcessRoteProcessVo::getId).collect(Collectors.toList());
            query.setProcessIds(CollectionUtils.isEmpty(processIds) ? Collections.singletonList(-1) : processIds);
        }
        Page<ReportGroupProcessInfo> data = this.baseMapper.workReportGroupByProcessList(page, query);
        // 获取报工信息
        List<String> processCodes = data.getRecords().stream().map(ReportGroupProcessInfo::getProcessCode).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(processCodes)) {
            query.setProcessCodes(processCodes);
            Map<String, List<WorkReportDetailVo>> dataGroupList = this.baseMapper.workReportListByProcessCodes(query).stream().collect(Collectors.groupingBy(WorkReportDetailVo::getProcessCode));
            if (!CollectionUtils.isEmpty(dataGroupList)) {
                data.getRecords().forEach(i ->
                        {
                            List<WorkReportDetailVo> workReportDetailVos = Optional.ofNullable(dataGroupList.get(i.getProcessCode())).orElse(Collections.emptyList());
                            if (workReportDetailVos.size() > query.getMaxDetailNum()) {
                                workReportDetailVos = workReportDetailVos.subList(0, query.getMaxDetailNum());
                            }
                            i.setGroupDetail(workReportDetailVos);
                        }
                );
            }
        }
        return data;
    }

    /**
     * 报工列表
     *
     * @param page  分页
     * @param query 请求参数
     */
    public Page<WorkReportListResp> getWorkReportList(Page<WorkReport> page, WorkReportListVo query) {
        Page<WorkReportListResp> data = this.getBaseMapper().getWorkReportList(page, query);
        ColumnUtils workReportColumnUtils = new ColumnUtils(customFieldService, ObjectType.workReport.getCode());
        Set<String> havePerProcessCodes = processesService.getPerByUserId(LoginUtil.getLoginUserId()).stream().map(Processes::getCode).collect(Collectors.toSet());
        data.getRecords().forEach(i -> {
            i.setCustomFieldVos(workReportColumnUtils.getCuColumnsByJsonArray(i.getOther()));
            i.setHandleState(havePerProcessCodes.contains(i.getProcessCode()));
        });
        return data;
    }

    /**
     * 获取任务二级分组数量
     *
     * @param screenPlanId      筛选方案id
     * @param mergeSearchResult 查询条件
     * @return 二级分组数量统计
     */
    public List<GroupCountVo> getSecondGroupTypeCount(Integer screenPlanId, WorkReportListVo mergeSearchResult) {
        List<GroupCountVo> typeCountData = new ArrayList<>();
        if (Objects.nonNull(screenPlanId)) {
            ScreenPlan screenPlan = screenPlanService.getById(screenPlanId);
            String secondGroup = screenPlan.getSecondGroup();
            Map<String, String> cnEnMap = ColumnUtils.BASE_COLUMN_CN_EN_MAP.getOrDefault(ObjectType.workReport.getCode(), Collections.emptyMap());
            String enName = cnEnMap.get(secondGroup);
            if (Objects.nonNull(enName)) {
                String resetEnName = (enName);
                mergeSearchResult.setSecondGroupColumnName(resetEnName);
                typeCountData.addAll(this.getTypeCountMap(mergeSearchResult, resetEnName));
            } else {
                // 自定义字段分组
                mergeSearchResult.setSecondGroupColumnName(secondGroup);
                CustomField customField = customFieldService.getById(secondGroup);
                if (Objects.nonNull(customFieldService.getById(secondGroup))) {
                    List<RadioOptionVo> options = JSONUtil.toList(Optional.ofNullable(customField.getCheckBox()).orElse("[]"), RadioOptionVo.class);
                    options.forEach(i -> {
                        List<Integer> workReportIds = customFieldService.searchCustomField(Collections.singletonMap(customField.getId(), i.getValue()), ObjectType.workReport.getCode());
                        mergeSearchResult.setIds(workReportIds);
                        long total = this.baseMapper.getGroupCountVo(mergeSearchResult);
                        typeCountData.add(new GroupCountVo().setOptionNum(total).setOptionName(i.getValue()).setOptionValue(i.getValue()).setTypeName(customField.getChineseName()));
                    });
                }
            }
        }
        return typeCountData;

    }


    /**
     * 获取分类统计数量
     *
     * @param searchCondition 查询条件
     * @return 类型数量映射
     */
    private Collection<? extends GroupCountVo> getTypeCountMap(WorkReportListVo searchCondition, String groupColumn) {
        Map<String, String> typeValueNameMap = new HashMap<>(10);
        List<String> typeChineseName = new ArrayList<>(1);
        switch (groupColumn) {
            case "verifyState":
                typeChineseName.add("审批状态");
                typeValueNameMap.put("0", "未审批");
                typeValueNameMap.put("1", "已审批");
                groupColumn = "verify_state";
                searchCondition.setVerifyState(null);
                break;
            case "pricingMethod":
                typeChineseName.add("计价方式");
                typeValueNameMap.put("0", "计件");
                typeValueNameMap.put("1", "计时");
                groupColumn = "pricing_method";
                searchCondition.setPricingMethod(null);
                break;
        }
        List<GroupCountVo> typeCountData = workReportService.getBaseMapper().getTypeCountMap(searchCondition, groupColumn);
        typeCountData.forEach(i -> {
            i.setTypeName(typeChineseName.get(0)).setOptionName(typeValueNameMap.get(i.getOptionValue()));
            typeValueNameMap.remove(i.getOptionValue());
        });
        typeValueNameMap.forEach((k, v) -> {
            typeCountData.add(new GroupCountVo().setOptionNum(0L).setTypeName(typeChineseName.get(0)).setOptionName(v).setOptionValue(k));
        });

        return typeCountData.stream().sorted(Comparator.comparingInt(f -> Integer.parseInt(f.getOptionValue()))).collect(Collectors.toList());
    }

    public Page<ProduceReportResp> getProduceReportList(Page<WorkReport> page, ProduceReportListVo searchCondition) {
        return this.workReportMapper.getProduceReportList(page,searchCondition);
    }
}
